#include "EItemMeta.h"
#include "EItem.h"
#include "EItemMetaFunction.h"

static char EItemMeta_typeStrArray[11][11] = {
    "int",
    "double",
    "bool",
    "long",
    "EVec3",
    "EVec4",
    "EColor",
    "EMatrix",
    "EString",
    "intptr_t",
    "empty"
};

struct EItemMetaData
{
    EList<EItemMetaPropertyPtr> m_propertys;
    EMap<EString, size_t> m_mapPropFastIndex;
    EList<EItemMetaFunctionPtr> m_functions;
    EMap<EString, size_t> m_mapFunFastIndex;
};

EItemMeta::EItemMeta()
{
    m_data = new EItemMetaData;
}

EItemMeta::~EItemMeta()
{
    delete m_data;
}

EString EItemMeta::getClassName()
{
    return m_className;
}

void EItemMeta::setClassName(const EString& className)
{
    m_className = className;
}


EString EItemMeta::getClassDescription()
{
    return m_classDescription;
}

void EItemMeta::setClassDescription(const EString& classDescription)
{
    m_classDescription = classDescription;
}

void EItemMeta::addProperty(EItemMetaPropertyPtr p)
{
    m_data->m_propertys.push_back(p);
    m_data->m_mapPropFastIndex[p->name] = m_data->m_propertys.size()-1;
}


void EItemMeta::addProperty(const EString& name, const EVariant& value)
{
    EItemMetaPropertyPtr newItem = NewSmartPtr(EItemMetaProperty)();
    newItem->typeName = EItemMeta_typeStrArray[value.m_type];
    newItem->name = name;
    newItem->value = value;
    
    this->addProperty(newItem);
}

EItemMetaPropertyPtr EItemMeta::getProperty(int index)
{
    EItemMetaPropertyPtr result = nullptr;
    if(index >=0 && index <m_data->m_propertys.size())
    {
        result = m_data->m_propertys[index];
    }
    return result;
}

EItemMetaPropertyPtr EItemMeta::getProperty(const EString& name)
{
    EItemMetaPropertyPtr result = nullptr;
    if(m_data->m_mapPropFastIndex.find(name) != m_data->m_mapPropFastIndex.end())
    {
        size_t index = m_data->m_mapPropFastIndex[name];
        if(index >=0 && index < m_data->m_propertys.size())
        {
            result = m_data->m_propertys[index];
        }
    }
    return result;
}

size_t EItemMeta::getPropertyCount()
{
    return m_data->m_propertys.size();
}
    
void EItemMeta::addFunction(EItemMetaFunctionPtr fun)
{
    m_data->m_functions.push_back(fun);
    m_data->m_mapFunFastIndex[fun->m_name] = m_data->m_functions.size()-1;
}

EItemMetaFunctionPtr EItemMeta::getFunction(int index)
{
    EItemMetaFunctionPtr result = nullptr;
    if(index >=0 && index <m_data->m_functions.size())
    {
        result = m_data->m_functions[index];
    }
    return result;
}

EItemMetaFunctionPtr EItemMeta::getFunction(const EString& name)
{
    EItemMetaFunctionPtr result = nullptr;
    if(m_data->m_mapFunFastIndex.find(name) != m_data->m_mapFunFastIndex.end())
    {
        size_t index = m_data->m_mapFunFastIndex[name];
        if(index >=0 && index < m_data->m_functions.size())
        {
            result = m_data->m_functions[index];
        }
    }
    return result;
}

size_t EItemMeta::getFunctionCount()
{
    return m_data->m_functions.size();
}

EString EItemMeta::getPrintStr()
{
    //TODO:the return value str is may be released for example in ELOG_DEBUG function:
    //ELOG_DEBUG("str=%s", itemMeta->getPrintStr().data())
    //In windows, code above will output empty content, because the returned EString is a function local value and its data is released.
    //In Linux, this code is right;
    EString str = "EItemMeta information:\n";

    str += EString("className=")+this->m_className+"\n";
    str += EString("property count=")+EString::number(this->m_data->m_propertys.size())+"\n";

    for(size_t i =0 ; i < this->m_data->m_propertys.size(); i++ )
    {
        str += EString::number(i) + " ";
        str += this->m_data->m_propertys[i]->name + " ";
        str += this->m_data->m_propertys[i]->value.getPrintStr()+" ";
        str += this->m_data->m_propertys[i]->groupName;
        str += "\n";
    }

    str += EString("function count=")+EString::number(this->m_data->m_functions.size())+"\n";

    for(size_t i =0 ; i < this->m_data->m_functions.size(); i++ )
    {
        str += EString::number(i) + " ";
        str += this->m_data->m_functions[i]->m_name + " ";
        str += this->m_data->m_functions[i]->getReturnProperty()->typeName + " ";
        str += "(";
        for(size_t j = 0 ; j < this->m_data->m_functions[i]->getPropertyCount(); j++)
        {
            str += this->m_data->m_functions[i]->getProperty(j)->typeName + ",";
        }
        
        str += ")\n";
    }

    return str;
}
